import tools from "./tools.js";

/**
 * 音频控制器类
 * 用于管理音频播放列表、播放状态、播放控制等功能
 */
class AudioController {
  /**
   * 构造函数
   * @param {Array} audioList - 音频列表，每个元素必须包含 url 属性
   * @param {Object} callbacks - 回调函数对象
   * @param {Function} callbacks.onAudioStart - 音频开始播放时的回调
   * @param {Function} callbacks.onAudioEnd - 单个音频播放结束时的回调
   * @param {Function} callbacks.onAllEnd - 所有音频播放结束时的回调
   * @param {Function} callbacks.onError - 音频播放错误时的回调
   * @param {Function} callbacks.onTimeUpdate - 音频播放时间更新时的回调
   */
  constructor(audioList = [], callbacks = {}) {
    // 深拷贝音频列表，避免外部修改影响内部数据
    this.audioList = tools.deepClone(audioList);
    // 当前播放的音频索引，-1表示未开始播放
    this.currentIndex = -1;
    // 当前播放的音频对象
    this.currentAudio = null;
    // uni.createInnerAudioContext创建的音频上下文
    this.audioContext = null;
    // 是否正在播放
    this.isPlaying = false;
    // 是否已销毁
    this.isDestroyed = false;
    // 播放倍速，默认1.0倍速
    this.playbackRate = 1.0;
    // 当前播放时间（秒）
    this.currentTime = 0;
    // 音频总时长（秒）
    this.duration = 0;
    // 时间更新定时器ID
    this.timeUpdateInterval = null;

    // 初始化回调函数，提供默认空函数防止未定义错误
    this.callbacks = {
      onAudioStart: callbacks.onAudioStart || (() => {}),
      onAudioEnd: callbacks.onAudioEnd || (() => {}),
      onAllEnd: callbacks.onAllEnd || (() => {}),
      onError: callbacks.onError || ((err) => console.error("音频错误:", err)),
      onTimeUpdate: callbacks.onTimeUpdate || (() => {}),
    };
  }

  /**
   * 初始化音频上下文
   * @param {string} url - 音频文件URL
   */
  initAudioContext(url) {
    // 如果已存在音频上下文，先销毁它
    if (this.audioContext) {
      this.audioContext.destroy();
    }

    // 创建新的音频上下文
    this.audioContext = uni.createInnerAudioContext();
    this.audioContext.src = url;
    this.audioContext.autoplay = false;

    // 音频开始播放事件
    this.audioContext.onPlay(() => {
      this.isPlaying = true;
      this.currentTime = 0;
      this.startTimeUpdate();
      this.callbacks.onAudioStart(this.currentAudio, this.currentIndex);
    });

    // 音频暂停事件
    this.audioContext.onPause(() => {
      this.isPlaying = false;
      this.stopTimeUpdate();
    });

    // 音频播放结束事件
    this.audioContext.onEnded(() => {
      this.stopTimeUpdate();
      this.handleAudioEnd();
    });

    // 音频播放错误事件
    this.audioContext.onError((err) => {
      this.callbacks.onError(err, this.currentAudio);
      this.isPlaying = false;
      this.stopTimeUpdate();
    });

    // 音频可以播放事件
    this.audioContext.onCanplay(() => {
      this.duration = this.audioContext.duration || 0;
      this.audioContext.playbackRate = this.playbackRate;
    });

    // 音频播放时间更新事件
    this.audioContext.onTimeUpdate(() => {
      this.currentTime = this.audioContext.currentTime || 0;
      this.duration = this.audioContext.duration || 0;
    });
  }

  /**
   * 开始时间更新定时器
   * 每100毫秒更新一次播放时间，并触发回调函数
   */
  startTimeUpdate() {
    // 先清除可能存在的定时器
    this.stopTimeUpdate();

    // 设置定时器，每100毫秒更新一次播放时间
    this.timeUpdateInterval = setInterval(() => {
      if (this.audioContext && this.isPlaying) {
        this.currentTime = this.audioContext.currentTime || 0;
        this.duration = this.audioContext.duration || 0;

        // 触发时间更新回调
        this.callbacks.onTimeUpdate(
          this.currentTime,
          this.duration,
          this.currentAudio,
          this.currentIndex
        );
      }
    }, 100);
  }

  /**
   * 停止时间更新定时器
   */
  stopTimeUpdate() {
    if (this.timeUpdateInterval) {
      clearInterval(this.timeUpdateInterval);
      this.timeUpdateInterval = null;
    }
  }

  /**
   * 处理音频播放结束事件
   * 触发音频结束回调，并决定播放下一个音频或结束所有播放
   */
  handleAudioEnd() {
    const prevAudio = this.currentAudio;
    const prevIndex = this.currentIndex;
    this.isPlaying = false;
    // 触发单个音频播放结束回调
    this.callbacks.onAudioEnd(prevAudio, prevIndex);

    // 判断是否还有下一个音频
    if (this.currentIndex < this.audioList.length - 1) {
      this.playNext();
    } else {
      // 所有音频播放完毕，触发结束回调
      this.callbacks.onAllEnd();
    }
  }

  /**
   * 按索引播放指定音频
   * @param {number} index - 音频索引
   */
  playByIndex(index) {
    // 检查控制器是否已销毁
    if (this.isDestroyed) return;

    // 检查索引是否有效
    if (index < 0 || index >= this.audioList.length) {
      this.callbacks.onError(new Error("索引超出范围"), null);
      return;
    }

    // 获取目标音频并更新当前状态
    const targetAudio = this.audioList[index];
    this.currentIndex = index;
    this.currentAudio = targetAudio;
    this.initAudioContext(targetAudio.url);

    // 设置播放倍速并开始播放
    this.audioContext.playbackRate = this.playbackRate;
    this.audioContext.play();
  }

  /**
   * 播放音频
   * @param {number} index - 可选，指定播放的音频索引
   */
  play(index) {
    // 检查控制器是否已销毁
    if (this.isDestroyed) return;

    // 检查音频列表是否为空
    if (this.audioList.length === 0) {
      this.callbacks.onError(new Error("音频列表为空"), null);
      return;
    }

    // 如果指定了有效索引，直接播放该索引的音频
    if (
      typeof index === "number" &&
      index >= 0 &&
      index < this.audioList.length
    ) {
      this.playByIndex(index);
      return;
    }

    // 如果正在播放，不执行任何操作
    if (this.isPlaying) return;

    // 如果是首次播放，播放第一个音频
    if (this.currentIndex === -1) {
      this.playByIndex(0);
    } else {
      // 否则恢复当前音频的播放
      this.audioContext.play();
    }
  }

  /**
   * 暂停音频播放
   */
  pause() {
    if (this.isDestroyed || !this.audioContext || !this.isPlaying) return;
    this.audioContext.pause();
  }

  /**
   * 播放下一个音频
   */
  playNext() {
    if (this.isDestroyed) return;
    // 检查是否已经是最后一个音频
    if (this.currentIndex >= this.audioList.length - 1) return;
    this.playByIndex(this.currentIndex + 1);
  }

  /**
   * 播放上一个音频
   */
  playPrev() {
    if (this.isDestroyed) return;
    // 检查是否已经是第一个音频
    if (this.currentIndex <= 0) return;
    this.playByIndex(this.currentIndex - 1);
  }

  /**
   * 切换播放/暂停状态
   */
  togglePlay() {
    if (this.isPlaying) {
      this.pause();
    } else {
      this.play();
    }
  }

  /**
   * 获取当前播放状态
   * @returns {Object} 包含播放状态信息的对象
   */
  getStatus() {
    return {
      isPlaying: this.isPlaying,
      currentAudio: this.currentAudio,
      currentIndex: this.currentIndex,
      totalCount: this.audioList.length,
      playbackRate: this.playbackRate,
    };
  }

  /**
   * 销毁音频控制器
   * 停止播放，释放资源，清空状态
   */
  destroy() {
    // 防止重复销毁
    if (this.isDestroyed) return;

    this.isDestroyed = true;
    this.isPlaying = false;

    // 停止并销毁音频上下文
    if (this.audioContext) {
      this.audioContext.stop();
      this.audioContext.destroy();
      this.audioContext = null;
    }

    // 清空状态
    this.audioList = [];
    this.currentIndex = -1;
    this.currentAudio = null;
  }

  /**
   * 重置音频控制器
   * 停止播放，重置状态，但不销毁控制器
   */
  reset() {
    // 如果已销毁，不执行任何操作
    if (this.isDestroyed) return;

    // 暂停播放
    this.pause();

    // 重置状态
    this.currentIndex = -1;
    this.currentAudio = null;

    // 销毁音频上下文
    if (this.audioContext) {
      this.audioContext.destroy();
      this.audioContext = null;
    }

    this.isPlaying = false;
  }

  /**
   * 设置播放倍速
   * @param {number} rate - 播放倍速，范围在0.5-2.0之间
   */
  setPlaybackRate(rate) {
    // 检查控制器是否已销毁
    if (this.isDestroyed) return;

    // 验证倍速值是否有效
    if (typeof rate !== "number" || rate < 0.5 || rate > 2.0) {
      this.callbacks.onError(new Error("播放速度必须在0.5-2.0之间"), null);
      return;
    }

    // 更新倍速值
    this.playbackRate = rate;

    // 如果音频上下文存在，应用新的倍速
    if (this.audioContext) {
      // 保存当前播放状态和时间
      const wasPlaying = this.isPlaying;
      const currentTime = this.audioContext.currentTime || 0;

      // 如果正在播放，先暂停
      if (wasPlaying) {
        this.audioContext.pause();
      }

      // 设置新的播放倍速
      this.audioContext.playbackRate = rate;

      // 如果之前在播放，恢复播放
      if (wasPlaying) {
        // 设置播放位置，确保倍速变更后能正确播放
        if (currentTime > 0) {
          this.audioContext.seek(currentTime);
        }
        this.audioContext.play();
      }
    }
  }

  /**
   * 获取当前播放倍速
   * @returns {number} 当前播放倍速
   */
  getPlaybackRate() {
    return this.playbackRate;
  }

  /**
   * 更新音频列表
   * @param {Array} newAudioList - 新的音频列表
   */
  updateAudioList(newAudioList) {
    // 检查控制器是否已销毁
    if (this.isDestroyed) return;

    // 深拷贝新的音频列表
    this.audioList = tools.deepClone(newAudioList);

    // 重置播放状态
    this.reset();
  }
}

export default AudioController;
